using UnityEngine;

namespace BuildingSystem.Scripts
{
    public class BuildingsGrid : MonoBehaviour
    {
        private const float GIZMOS_SPHERE_RADIUS = .05f;
        private const float GIZMOS_CELL_RADIUS = .9f;

        [SerializeField] private Vector2Int _size = Vector2Int.one;

        public Plane GridPlane { get; private set; }

        private uint _currentID = 1;
        private uint[,] _matrix;

        private void Awake()
        {
            if (!Utils.IsInt(transform.position.x) || !Utils.IsInt(transform.position.z))
                throw new System.Exception("transform.position must be Vector2Int");

            GridPlane = new(Vector3.up, Vector3.zero);

            _matrix = new uint[_size.x, _size.y];
        }   

        public Vector2Int WorldToGridPoint(Vector3 worldPoint)
        {
            var x = Mathf.RoundToInt(worldPoint.x);
            var y = Mathf.RoundToInt(worldPoint.z);

            var gridPoint = new Vector2Int(x, y);

            return gridPoint;
        }

        public bool CanSet(Building building)
        {
            var buildingRect = building.Rect;
            var buildingSize =Utils.ToVector2Int(buildingRect.size);
            var gridPoint = Utils.ToVector2Int(buildingRect.position);
            var matrxiPoint = GridToMatrixPoint(gridPoint);
            
            if (!Utils.InRange(matrxiPoint.x, 0, _size.x - buildingSize.x + 1))
                return false;
            if (!Utils.InRange(matrxiPoint.y, 0, _size.y - buildingSize.y + 1))
                return false;

            for (int x = 0; x < buildingSize.x; x++)
                for (int y = 0; y < buildingSize.y; y++)
                    if (_matrix[matrxiPoint.x + x, matrxiPoint.y + y] != 0)
                        return false;
            
            return true;
        }

        public void Set(Building building)
        {
            var buildingRect = building.Rect;
            var buildingSize = Utils.ToVector2Int(buildingRect.size);
            var gridPoint = Utils.ToVector2Int(buildingRect.position);

            for (int x = 0; x < buildingSize.x; x++)
                for (int y = 0; y < buildingSize.y; y++)
                {
                    var matrixPoint = GridToMatrixPoint(gridPoint + new Vector2Int(x, y));
                    _matrix[matrixPoint.x, matrixPoint.y] = _currentID;
                }

            _currentID++;
        }

        private Vector2Int GridToMatrixPoint(Vector2Int gridPoint) =>
            new Vector2Int(gridPoint.x - (int)transform.position.x, gridPoint.y - (int)transform.position.z);

        private void OnDrawGizmos()
        {
            Gizmos.color = Color.green;
            Gizmos.DrawWireCube(transform.position + new Vector3(_size.x - 1, 0, _size.y - 1) / 2f, new Vector3(_size.x, 0, _size.y));
            for (int x = 0; x < _size.x; x++)
                for (int y = 0; y < _size.y; y++)
                    Gizmos.DrawSphere(transform.position + new Vector3(x, 0, y), GIZMOS_SPHERE_RADIUS);

            if (_matrix != null)
            {
                Gizmos.color = Color.cyan;
                for (int x = 0; x < _size.x; x++)
                    for (int y = 0; y < _size.y; y++)
                        if (_matrix[x, y] != 0)
                            Gizmos.DrawWireCube(transform.position + new Vector3(x, 0, y), new Vector3(1, 0, 1) * GIZMOS_CELL_RADIUS);
            }
        }
    }
}